package com.xujl.task.dual;

import com.xujl.task.Emitter;
import com.xujl.task.RxExecutor;
import com.xujl.task.Task;

import java.util.concurrent.LinkedBlockingQueue;

/**
 * 双线ui任务管理器
 * 一个运行在子线程上的阻塞队列
 * 每个任务完成后会回调一次主线程
 * 与RxFollow的区别在于RxFollow强调流程，
 * 且RxFollow单个任务需要手动调用完成，任务是否完成
 * 对于RxFollow是未知的。
 * DualManager强调的是与ui线程间的自动切换
 * 子线程代码执行后会自动切换到下一个
 * DualManager子线程任务不支持在里面异步调用（RxFollow支持）
 * DualManager任务是运行在子线程中,耗时操作不会引起anr
 * 但是不建议直接把耗时比较长的任务直接写在run内，因为
 * DualManager是单线程顺序执行模型，耗时过久会影响后续加载逻辑
 */
public class DualManager {
    private static final String TAG = "DualManager";
    private LinkedBlockingQueue<Callback> mQueue;
    private boolean isExit;

    private DualManager () {
    }

    public static DualManager getInstance () {
        return Holder.MANAGER;
    }

    public void init () {
        this.init(50);
    }

    /**
     * @param queueSize 队列最大长度
     */
    public void init (int queueSize) {
        mQueue = new LinkedBlockingQueue<>(queueSize);
        start();
        RxExecutor.getInstance().executeTask(mTask);
    }

    private void start () {
        mTask = new Task<Callback>() {
            @Override
            public void run (Emitter<Callback> emitter) throws Exception {
                super.run(emitter);
                while (!isExit) {
                    final Callback callback = mQueue.take();
                    boolean needCallback = false;
                    try {
                        needCallback = callback.run(emitter);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if (needCallback) {
                        emitter.next(callback);
                    }
                }
            }

            @Override
            public void onNext (Callback data) {
                super.onNext(data);
                data.main();
            }
        };
    }

    private Task<Callback> mTask;

    public void addTasks (Callback... callbacks) {
        if (callbacks == null) {
            return;
        }
        try {
            for (Callback callback : callbacks) {
                mQueue.put(callback);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void exit () {
        isExit = true;
        mTask = null;
        mQueue = null;
    }


    public static class DualBuilder {

    }

    private static class Holder {
        private static final DualManager MANAGER = new DualManager();
    }

    public abstract static class Callback {
        private Object data;

        public Object getData () {
            return data;
        }

        public void setData (Object data) {
            this.data = data;
        }

        /**
         * @param emitter
         * @return 是否需要回调主线程
         */
        public abstract boolean run (Emitter<Callback> emitter);

        public void main () {
        }
    }
}
